using System;
using System.Collections.Generic;
using System.IO;
using OpenCvSharp;
using OpenCvSharp.Face;

namespace FaceRecognition
{
    public class FaceRecognizer
    {
        private readonly string _trainingDataPath;
        private readonly string _modelPath;
        private readonly string _cascadeFilePath = "haarcascade_frontalface_default.xml";
        private CascadeClassifier _faceCascade;
        private LBPHFaceRecognizer _recognizer;
        private List<int> _labels = new List<int>();
        private List<Mat> _faces = new List<Mat>();

        public FaceRecognizer(string trainingDataPath, string modelPath)
        {
            _trainingDataPath = trainingDataPath;
            _modelPath = modelPath;

            // 初始化人脸检测器
            if (File.Exists(_cascadeFilePath))
            {
                _faceCascade = new CascadeClassifier(_cascadeFilePath);
            }
            else
            {
                throw new FileNotFoundException("人脸检测模型文件未找到", _cascadeFilePath);
            }

            // 初始化识别器
            _recognizer = LBPHFaceRecognizer.Create();
        }

        // 准备训练数据
        public void PrepareTrainingData()
        {
            Console.WriteLine("开始准备训练数据...");

            // 获取所有人员目录
            string[] personFolders = Directory.GetDirectories(_trainingDataPath);

            for (int i = 0; i < personFolders.Length; i++)
            {
                string personName = Path.GetFileName(personFolders[i]);
                Console.WriteLine($"正在处理 {personName} 的人脸数据...");

                // 获取该人员的所有图片
                string[] imageFiles = Directory.GetFiles(personFolders[i], "*.*", SearchOption.TopDirectoryOnly);

                foreach (string imageFile in imageFiles)
                {
                    try
                    {
                        // 读取图片并检测人脸
                        Mat face = DetectFace(imageFile);
                        if (!face.Empty())
                        {
                            _faces.Add(face);
                            _labels.Add(i); // 使用目录索引作为标签
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"处理图片 {imageFile} 时出错: {ex.Message}");
                    }
                }
            }

            if (_faces.Count == 0)
            {
                throw new Exception("未检测到任何人脸，请检查训练数据");
            }

            Console.WriteLine($"共检测到 {_faces.Count} 张人脸，开始训练模型...");

            // 训练模型
            _recognizer.Train(_faces, _labels);
            _recognizer.Save(_modelPath);

            Console.WriteLine($"模型训练完成，已保存到 {_modelPath}");
        }

        // 检测人脸并返回预处理后的人脸图像
        public Mat DetectFace(string imagePath)
        {
            using (Mat image = Cv2.ImRead(imagePath))
            {
                if (image.Empty())
                {
                    throw new Exception($"无法读取图片: {imagePath}");
                }

                // 转为灰度图
                using (Mat gray = new Mat())
                {
                    Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);

                    // 直方图均衡化，增强对比度
                    Cv2.EqualizeHist(gray, gray);

                    // 检测人脸
                    Rect[] faces = _faceCascade.DetectMultiScale(
                        gray,
                        1.1,
                        3,
                        HaarDetectionTypes.ScaleImage,
                        new Size(30, 30)
                    );

                    if (faces.Length == 0)
                    {
                        return new Mat(); // 未检测到人脸
                    }

                    // 取第一个检测到的人脸
                    Rect faceRect = faces[0];
                    Mat face = new Mat(gray, faceRect);

                    // 调整人脸图像大小为统一尺寸
                    Cv2.Resize(face, face, new Size(100, 100));

                    return face;
                }
            }
        }

        // 识别人脸
        public (int label, double confidence) RecognizeFace(string imagePath)
        {
            if (!File.Exists(_modelPath))
            {
                throw new Exception("模型文件不存在，请先训练模型");
            }

            _recognizer.Read(_modelPath);

            using (Mat face = DetectFace(imagePath))
            {
                if (face.Empty())
                {
                    throw new Exception("未在图片中检测到人脸");
                }

                _recognizer.Predict(face, out int label, out double confidence);
                return (label, confidence);
            }
        }

        // 比较两个人脸的相似度
        public double CompareFaces(string facePath1, string facePath2)
        {
            using (Mat face1 = DetectFace(facePath1))
            using (Mat face2 = DetectFace(facePath2))
            {
                if (face1.Empty() || face2.Empty())
                {
                    throw new Exception("无法从一个或多个图片中检测到人脸");
                }

                // 使用直方图比较相似度
                Mat hist1 = CalculateHistogram(face1);
                Mat hist2 = CalculateHistogram(face2);

                return Cv2.CompareHist(hist1, hist2, HistCompMethods.Correl);
            }
        }

        // 计算图像直方图 - 修复了Rangef类型错误
        private Mat CalculateHistogram(Mat image)
        {
            Mat hist = new Mat();
            Mat[] images = { image };
            int[] channels = { 0 };
            int[] histSize = { 256 };

            // 修正：使用Rangef类型而不是int数组
            Rangef[] ranges = { new Rangef(0, 256) };

            // 计算直方图
            Cv2.CalcHist(images, channels, new Mat(), hist, 1, histSize, ranges);
            Cv2.Normalize(hist, hist, 0, 1, NormTypes.MinMax);

            return hist;
        }
    }
}
